my $mc = 'A';
my $lh = 0;
my $ll = 0;
my $reply = 0;
my $linecntr = 0;
my $file = shift;

open KOKOS, "<$file" or die "File $file cannot be open!\n";

binmode KOKOS;

while(1) {
	read(KOKOS, $mc, 1) or die "--------: EOF\n";
	$linecntr = tell(KOKOS);

	if( ord($mc) == 0xff ) {
		$pnxt = 1;
		next;
	}

	if( defined($pnxt) ) {
		if( ord($mc) == 0xd8) {
			printf("%8.8x: SOI\n", $linecntr-1 );
			undef($pnxt);
			next;
 		}
		if( ord($mc) == 0xd9) {
			printf("%8.8x: EOI\n", $linecntr-1 );
			undef($pnxt);
			next;
 		}
		if( ord($mc) == 0xda) { #"Start of scan";
			printf("%8.8x: SOS\n", $linecntr-1 );
			undef($pnxt);
			next;
 		}

#	Restart interval termination

		if( ord($mc) == 0xD0){ #"Restart with modulo 8 count 0";
	   	printf("%8.8x: RST0\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD1){ #"Restart with modulo 8 count 1";
   		printf("%8.8x: RST1\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD2){ #"Restart with modulo 8 count 2";
   		printf("%8.8x: RST2\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD3){ #"Restart with modulo 8 count 3";
   		printf("%8.8x: RST3\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD4){ #"Restart with modulo 8 count 4";
   		printf("%8.8x: RST4\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD6){ #"Restart with modulo 8 count 5";
   		printf("%8.8x: RST5\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD6){ #"Restart with modulo 8 count 6";
   		printf("%8.8x: RST6\n", $linecntr-1 );
			undef($pnxt);
			next;
		}
		if( ord($mc) == 0xD7){ #"Restart with modulo 8 count 7";
   		printf("%8.8x: RST7\n", $linecntr-1 );
			undef($pnxt);
			next;
		}

#	Arithmetic coding conditioning specification

		if( ord($mc) == 0xCC){ #"Define arithmetic coding conditioning(s)";
	   	printf("%8.8x: DAC\n", $linecntr-1 );
			next;
		}


		&display( 'DQT' ) if( ord( $mc ) == 0xdb); #"Define quantization table(s)";
		&display( 'DNL' ) if( ord( $mc ) == 0xdc); #"Define number of lines";
		&display( 'DRI' ) if( ord( $mc ) == 0xdd); #"Define restart interval";
		&display( 'DPH' ) if( ord( $mc ) == 0xde); #"Define hierarchical progression";
		&display( 'EXP' ) if( ord( $mc ) == 0xdf); #"Expand reference component(s)";
		&display_SOF0( 'SOF0' ) if( ord( $mc ) == 0xC0); #"Baseline DCT";
   	&display( 'SOF1' ) if( ord( $mc ) == 0xC1); #"Extended sequential DCT";
   	&display( 'SOF2' ) if( ord( $mc ) == 0xC2); #"Progressive DCT";
   	&display( 'SOF3' ) if( ord( $mc ) == 0xC3); #"Lossless (sequential)";
   	&display( 'DHT' ) if( ord( $mc ) == 0xC4); #"Huffmann table
#
#	Start Of Frame markers, differential, Huffman coding

   	&display( 'SOF5' ) if( ord( $mc ) == 0xC5); #"Differential sequential DCT";
   	&display( 'SOF6' ) if( ord( $mc ) == 0xC6); #"Differential progressive DCT";
   	&display( 'SOF7' ) if( ord( $mc ) == 0xC7); #"Differential lossless (sequential)";

#	Start Of Frame markers, non-differential, arithmetic coding

   	&display( 'JPG' ) if( ord( $mc ) == 0xC8); #"Reserved for JPEG extensions";
   	&display( 'SOF9' ) if( ord( $mc ) == 0xC9); #"Extended sequential DCT";
   	&display( 'SOF10' ) if( ord( $mc ) == 0xCA); #"Progressive DCT";
   	&display( 'SOF11' ) if( ord( $mc ) == 0xCB); #"Lossless (sequential)";

#	Start Of Frame markers, differential, arithmetic coding

   	&display( 'SOF13' ) if( ord( $mc ) == 0xCD); #"Differential sequential DCT";
   	&display( 'SOF14' ) if( ord( $mc ) == 0xCE); #"Differential progressive DCT";
   	&display( 'SOF15' ) if( ord( $mc ) == 0xCF); #"Differential lossless (sequential)";

		&display( 'APP0' ) if( ord( $mc ) == 0xe0); #"Reserved for application segments";
		&display( 'APP1' ) if( ord( $mc ) == 0xe1); #"Reserved for application segments";
		&display( 'APP2' ) if( ord( $mc ) == 0xe2); #"Reserved for application segments";
		&display( 'APP3' ) if( ord( $mc ) == 0xe3); #"Reserved for application segments";
		&display( 'APP4' ) if( ord( $mc ) == 0xe4); #"Reserved for application segments";
		&display( 'APP5' ) if( ord( $mc ) == 0xe5); #"Reserved for application segments";
		&display( 'APP6' ) if( ord( $mc ) == 0xe6); #"Reserved for application segments";
		&display( 'APP7' ) if( ord( $mc ) == 0xe7); #"Reserved for application segments";
		&display( 'APP8' ) if( ord( $mc ) == 0xe8); #"Reserved for application segments";
		&display( 'APP9' ) if( ord( $mc ) == 0xe9); #"Reserved for application segments";
		&display( 'APP10' ) if( ord( $mc ) == 0xea); #"Reserved for application segments";
		&display( 'APP11' ) if( ord( $mc ) == 0xeb); #"Reserved for application segments";
		&display( 'APP12' ) if( ord( $mc ) == 0xec); #"Reserved for application segments";
		&display( 'APP13' ) if( ord( $mc ) == 0xed); #"Reserved for application segments";
		&display( 'APP14' ) if( ord( $mc ) == 0xee); #"Reserved for application segments";
		&display( 'APP15' ) if( ord( $mc ) == 0xef); #"Reserved for application segments";

		&display( 'JPG0' ) if( ord( $mc ) == 0xf0); #"Reserved for JPEG extensions";
		&display( 'JPG1' ) if( ord( $mc ) == 0xf1); #"Reserved for JPEG extensions";
		&display( 'JPG2' ) if( ord( $mc ) == 0xf2); #"Reserved for JPEG extensions";
		&display( 'JPG3' ) if( ord( $mc ) == 0xf3); #"Reserved for JPEG extensions";
		&display( 'JPG4' ) if( ord( $mc ) == 0xf4); #"Reserved for JPEG extensions";
		&display( 'JPG5' ) if( ord( $mc ) == 0xf5); #"Reserved for JPEG extensions";
		&display( 'JPG6' ) if( ord( $mc ) == 0xf6); #"Reserved for JPEG extensions";
		&display( 'JPG7' ) if( ord( $mc ) == 0xf7); #"Reserved for JPEG extensions";
		&display( 'JPG8' ) if( ord( $mc ) == 0xf8); #"Reserved for JPEG extensions";
		&display( 'JPG9' ) if( ord( $mc ) == 0xf9); #"Reserved for JPEG extensions";
		&display( 'JPG10' ) if( ord( $mc ) == 0xfa); #"Reserved for JPEG extensions";
		&display( 'JPG11' ) if( ord( $mc ) == 0xfb); #"Reserved for JPEG extensions";
		&display( 'JPG12' ) if( ord( $mc ) == 0xfc); #"Reserved for JPEG extensions";
		&display( 'JPG13' ) if( ord( $mc ) == 0xfd); #"Reserved for JPEG extensions";

		&display( 'COM' ) if( ord($mc) == 0xfe); #"Comment";
	}

	undef($pnxt);
}

close( KOKOS );

print "---- END ----\n";

sub display {
	my $str = shift;
	my $pos = tell(KOKOS) - 1;
	read(KOKOS, $lh, 1) or die "--------: EOF\n";
	read(KOKOS, $ll, 1) or die "--------: EOF\n";
	printf("%8.8x: %s [len: %8.8x]\n", $pos, $str, (ord($lh)*256 + ord($ll)) ); 
	seek(KOKOS,((ord($lh)*256 + ord($ll))-4),1);
}

sub display_SOF0 {
	my ($tmp,$cntr, $lowbyte,$highbyte);
	my $str = shift;
	my $pos = tell(KOKOS) - 1;
	read(KOKOS, $lh, 1) or die "--------: EOF\n";
	read(KOKOS, $ll, 1) or die "--------: EOF\n";
	printf("%8.8x: %s (Baseline DTC) [payload length: %8.8x]\n", $pos, $str, (ord($lh)*256 + ord($ll)) ); 
	printf("\tFrame structure:\n" );

	read(KOKOS, $tmp, 1) or die "--------: EOF\n";
	printf("\tSampling precision: %d bits/sample\n", ord($tmp) );

	read(KOKOS, $highbyte, 1) or die "--------: EOF\n";
	read(KOKOS, $lowbyte, 1) or die "--------: EOF\n";
	printf("\tImage heigh %4.4d pixels\n", (ord($highbyte)*256 + ord($lowbyte)) ); 

	read(KOKOS, $highbyte, 1) or die "--------: EOF\n";
	read(KOKOS, $lowbyte, 1) or die "--------: EOF\n";
	printf("\tImage width %4.4d pixels\n", (ord($highbyte)*256 + ord($lowbyte)) ); 

	read(KOKOS, $tmp, 1) or die "--------: EOF\n";
	$tmp = ord($tmp);
	if( $tmp == 1 ) {
		print("\tgrayscale\n");
	} elsif( $tmp == 3 ) {
		print("\tcolor YCbCr\n");
	} elsif( $tmp == 4 ) {
		print("\tcolor CMYK\n");
	} else {
		printf("\tunrecognized color space coded as: %2.2x, bailing out SOF0 analysis.\n", $tmp );
#		seek(KOKOS,((ord($lh)*256 + ord($ll))-4),1);
		return;
	}

	$cntr = $tmp;

	for( $i=0; $i < $cntr; $i++ ) {
		read(KOKOS, $tmp, 1) or die "--------: EOF\n";
		printf("\t\tComponent ID: %x (1-Y, 2-Cb, 3-Cr, 4-I, 5-Q)\n", ord($tmp) );
		read(KOKOS, $tmp, 1) or die "--------: EOF\n";
		$tmp = ord($tmp);
		printf("\t\tSampling factors vertical: %x\n", ($tmp & 0xF));
		printf("\t\tSampling factors horizontal: %x\n", (($tmp & 0xF0)>>4));
		read(KOKOS, $tmp, 1) or die "--------: EOF\n";
		printf("\t\tQuantitization Table Index: %x\n", ord($tmp));
	}

#	seek(KOKOS,((ord($lh)*256 + ord($ll))-4),1);
}

=cut

0xFF 0xC0 (SOF0 identifier)
length (high byte, low byte), 8+components*3
data precision (1 byte) in bits/sample, usually 8 (12 and 16 not supported by most software)
image height (2 bytes, Hi-Lo), must be >0 if DNL not supported
image width (2 bytes, Hi-Lo), must be >0 if DNL not supported
number of components (1 byte), usually 1 = grey scaled, 3 = color YCbCr or YIQ, 4 = color CMYK)
for each component: 3 bytes
component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
sampling factors (bit 0-3 vert., 4-7 hor.)
quantization table number
